#
# This CMakeLists file will generate the file elxSupportedImageTypes.h
# in the bin directory. This file defines the types of images for which
# elastix is compiled.
#

# User specified variables:
mark_as_advanced( ELASTIX_IMAGE_DIMENSIONS )
set( ELASTIX_IMAGE_DIMENSIONS 2 3 4 CACHE STRING "Specify image dimensions" )

mark_as_advanced( ELASTIX_IMAGE_2D_PIXELTYPES )
set( ELASTIX_IMAGE_2D_PIXELTYPES "float" CACHE STRING "Specify 2D pixel types" )

mark_as_advanced( ELASTIX_IMAGE_3D_PIXELTYPES )
set( ELASTIX_IMAGE_3D_PIXELTYPES "short" "float" CACHE STRING "Specify 3D pixel types" )

mark_as_advanced( ELASTIX_IMAGE_4D_PIXELTYPES )
set( ELASTIX_IMAGE_4D_PIXELTYPES "short" "float" CACHE STRING "Specify 4D pixel types" )

# Define supported dimensions and types for sanity checks.
# Gives protection against typo's.
set( supportedDimensions 2 3 4 )
set( supportedTypes "char" "unsigned char"
  "short" "unsigned short" "int" "unsigned int"
  "long" "unsigned long" "float" "double" )

# Sanity check if > 0 number of dimensions are requested
list( LENGTH ELASTIX_IMAGE_DIMENSIONS numDims )
if( ${numDims} EQUAL 0 )
  message( FATAL_ERROR "ERROR: you should set one or more values "
    " to ELASTIX_IMAGE_DIMENSIONS!\n"
    "Choose a subset of {${supportedDimensions}}." )
endif()

# Start a string containing the supported image types
# and initialize some variables.
set( supportString "" )
set( supportOpenCLImages "" )
set( index 1 )
set( numSupported 0 )

# Add supported image types to the string
foreach( dim ${ELASTIX_IMAGE_DIMENSIONS} )

  # Check dimension
  if( ${dim} EQUAL 2 )
    set( pixelTypeList ${ELASTIX_IMAGE_2D_PIXELTYPES} )
    set( whichList "ELASTIX_IMAGE_2D_PIXELTYPES" )
  elseif( ${dim} EQUAL 3 )
    set( pixelTypeList ${ELASTIX_IMAGE_3D_PIXELTYPES} )
    set( whichList "ELASTIX_IMAGE_3D_PIXELTYPES" )
  elseif( ${dim} EQUAL 4 )
    set( pixelTypeList ${ELASTIX_IMAGE_4D_PIXELTYPES} )
    set( whichList "ELASTIX_IMAGE_4D_PIXELTYPES" )
  else()
    message( FATAL_ERROR "ERROR: you selected ELASTIX_IMAGE_DIMENSIONS"
      " to include ${dim}, which is not supported!\n"
      "Choose a subset of {${supportedDimensions}}." )
  endif()

  # Sanity check if > 0 number of pixel types are requested
  list( LENGTH pixelTypeList pixelTypeListLength )
  if( ${pixelTypeListLength} EQUAL 0 )
    message( FATAL_ERROR "ERROR: you should set one or more values"
      " to ${whichList}!\n"
      "Choose a subset of {${supportedTypes}}." )
  endif()

  # Add types
  foreach( type ${pixelTypeList} )
    # Sanity check
    list( FIND supportedTypes ${type} foundIndex )
    if( ${foundIndex} EQUAL -1 )
      message( FATAL_ERROR "ERROR: you selected ${whichList}"
        " to include ${type}, which is not supported!\n"
        "Choose a subset of {${supportedTypes}}." )
    endif()

    # Add type to supportString
    set( supportString
      "${supportString}  elxSupportedImageTypeMacro( ${type}, ${dim}, ${type}, ${dim}, ${index} );\n" )

    # Increase some variables
    math( EXPR index "${index} + 1" )
    math( EXPR numSupported "${numSupported} + 1" )
  endforeach()

  # OpenCL
  if( ELASTIX_USE_OPENCL )
    # Construct supportOpenCLImages
    set( openclindex 0 )
    list( LENGTH pixelTypeList pixelTypeListLength )

    if( supportOpenCLImages STREQUAL "" )
      set( supportOpenCLImages "typedef typelist::MakeTypeList<" )
    else()
      set( supportOpenCLImages "${supportOpenCLImages}\n  typedef typelist::MakeTypeList<" )
    endif()

    foreach( type ${pixelTypeList} )
      set( supportOpenCLImages "${supportOpenCLImages}${type}" )
      math( EXPR openclindex "${openclindex} + 1" )
      if( NOT openclindex EQUAL pixelTypeListLength )
        set( supportOpenCLImages "${supportOpenCLImages}, " )
      endif()
    endforeach()
    set( supportOpenCLImages "${supportOpenCLImages}>::Type OpenCLImageTypes${dim}D;" )
  endif()

endforeach()

# Prepend the string with the number of supported images.
set( supportString
  "const unsigned int NrOfSupportedImageTypes = ${numSupported};\n\n${supportString}" )

# Put the generated string in the elxSupportedImageTypes.h
# header using configure_file.
set( UserDefinedSupportedImageTypes ${supportString} )
configure_file(
  ${elastix_SOURCE_DIR}/Core/Install/elxSupportedImageTypes.h.in
  ${elastix_BINARY_DIR}/elxSupportedImageTypes.h
  @ONLY )

# OpenCL
if( ELASTIX_USE_OPENCL )
  # Construct supportOpenCLDimensions
  set( supportOpenCLDimensions "" )

  # Check 2D
  list( FIND ELASTIX_IMAGE_DIMENSIONS 2 ELASTIX_SUPPORT_OPENCL_2D )
  if( NOT ELASTIX_SUPPORT_OPENCL_2D EQUAL -1 )
    set( tof "true" )
  else()
    set( tof "false" )
  endif()
  set( supportOpenCLDimensions "itkStaticConstMacro( Support2D, bool, ${tof} );" )

  # Check 3D
  list( FIND ELASTIX_IMAGE_DIMENSIONS 3 ELASTIX_SUPPORT_OPENCL_3D )
  if( NOT ELASTIX_SUPPORT_OPENCL_3D EQUAL -1 )
    set( tof "true" )
  else()
    set( tof "false" )
  endif()
  set( supportOpenCLDimensions
    "${supportOpenCLDimensions}\n    itkStaticConstMacro( Support3D, bool, ${tof} );" )

  set( UserDefinedSupportedDimensions "${supportOpenCLDimensions}" )
  set( UserDefinedSupportedImageTypes "${supportOpenCLImages}" )

  # Put the generated string in the elxOpenCLSupportedImageTypes.h
  # header using configure_file.
  configure_file(
    ${elastix_SOURCE_DIR}/Core/Install/elxOpenCLSupportedImageTypes.h.in
    ${elastix_BINARY_DIR}/elxOpenCLSupportedImageTypes.h
    @ONLY )
endif()

